package com.sky.service.courier.impl;

import cn.hutool.core.util.ObjectUtil;
import cn.hutool.core.util.StrUtil;
import com.sky.constant.MessageConstant;
import com.sky.constant.RedisConstant;
import com.sky.dto.UserLoginDTO;
import com.sky.exception.BaseException;
import com.sky.exception.ParameterInvalidException;
import com.sky.exception.ParameterIsNullException;
import com.sky.mapper.common.OrdersMapper;
import com.sky.mapper.common.ShortUrlMapper;
import com.sky.mapper.courier.CourierMapper;
import com.sky.mapper.courier.CourierTradeOrderMapper;
import com.sky.pojo.Courier;
import com.sky.pojo.CourierTradeOrder;
import com.sky.pojo.Orders;
import com.sky.pojo.ShortUrl;
import com.sky.service.courier.CourierService;
import com.sky.shoturi.ShortUrlGenerator;
import com.sky.sms.core.AliyunSmsTemplate;
import com.sky.utils.RandomCode;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.time.LocalDateTime;
import java.util.concurrent.TimeUnit;

/**
 * 骑手业务实现
 * @author zgp
 * @version V1.0
 * @date 2025-02-11 20:08
 */
@Slf4j
@Service
public class CourierServiceImpl implements CourierService {
    @Autowired
    private AliyunSmsTemplate aliyunSmsTemplate;
    @Autowired
    private RedisTemplate redisTemplate;
    @Autowired
    private CourierMapper courierMapper;
    @Autowired
    private OrdersMapper ordersMapper;
    @Autowired
    private CourierTradeOrderMapper courierTradeOrderMapper;
    @Autowired
    private ShortUrlGenerator shortUrlGenerator;
    @Autowired
    private ShortUrlMapper shortUrlMapper;


    @Override
    public String getSmsCode(String telephone) {
        // 校验手机号
        if(StrUtil.isEmpty(telephone)){
            throw new ParameterIsNullException(MessageConstant.PHONE_IS_NULL);
        }
        // 手机号合法性校验
        /*if(!IdentityUtil.validatePhone(telephone)){
            throw new ParameterInvalidException(MessageConstant.PHONE_IS_INVALID);
        }*/
        String code = RandomCode.getRandomCode();
        /*// 发送短信验证码
        aliyunSmsTemplate.sendMessage(telephone, code);*/
        // 写入缓存
        redisTemplate.opsForValue().set(RedisConstant.COURIER_LOGIN_CODE_PREFIX + telephone, code, 5, TimeUnit.MINUTES);
        return code;
    }

    @Override
    public Courier login(UserLoginDTO userLoginDTO) {
        // 校验参数
        if(ObjectUtil.isNull(userLoginDTO)
                || ObjectUtil.isNull(userLoginDTO.getTelephone())
                || ObjectUtil.isNull(userLoginDTO.getCode())){
            throw new ParameterInvalidException(MessageConstant.PARAMES_IS_INVALID);
        }
        // 根据手机号查询骑手
        Courier courier = courierMapper.selectByTelephone(userLoginDTO.getTelephone());
        if(ObjectUtil.isNull(courier)){
            throw new BaseException("当前手机号未注册");
        }
        String redisKey = RedisConstant.COURIER_LOGIN_CODE_PREFIX + userLoginDTO.getTelephone();
        // 校验验证码是否正确
        String code = (String) redisTemplate.opsForValue().get(redisKey);
        if(StrUtil.isEmpty(code)){
            throw new BaseException("验证码已过期");
        }
        if(!code.equals(userLoginDTO.getCode())){
            redisTemplate.delete(redisKey);
            throw new BaseException("验证码错误");
        }
        // 校验通过，登录成功
        redisTemplate.delete(redisKey);
        return courier;
    }

    @Override
    @Transactional(rollbackFor = {Exception.class})
    public void receivingOrder(Integer courierId, Long tradeNo) {
        // 根据运单号查询运单
        CourierTradeOrder courierTradeOrder = courierTradeOrderMapper.selectByTradeNo(tradeNo);
        if(ObjectUtil.isNull(courierTradeOrder)){
            throw new ParameterInvalidException("运单不存在");
        }
        // 修改运单状态：骑手接单，开启配送中 DELIVORING
        courierTradeOrder.setWaybillStatus(CourierTradeOrder.DELIVORING);
        courierTradeOrderMapper.updateByTradeNo(courierTradeOrder);
        // 修改订单状态：骑手接单成功-待取货
        Orders orders = Orders.builder()
                .number(courierTradeOrder.getOrderNumber())
                .status(Orders.TOBEPICKEDUP)
                .build();
        ordersMapper.updateByNumber(orders);
        // 发送短链短信
        sendShotUrlMessage(courierTradeOrder);
        // 短信通知用户，附带短链
        // 生成短链-全链，保存到数据库
        // 发送短信附带生成的短链信息
        // 用户访问短链，解析短链，根据短链对应长链重定向到指定页面。
    }

    /**
     * 发送短链信息（用于地图查看骑手位置信息）
     * @param courierTradeOrder 运单信息
     */
    private void sendShotUrlMessage(CourierTradeOrder courierTradeOrder) {
        // 生成唯一短链code
        String shortCode = generateShortCode(courierTradeOrder.getOrderNumber());
        // 生成短链
        String shortUrl = shortUrlGenerator.getShortUrl(shortCode);
        // 生成全链
        LocalDateTime customerExpectedDeliveryTime = courierTradeOrder.getCustomerExpectedDeliveryTime();
        Long tradeNo = courierTradeOrder.getTradeNo();
        String fullUrl = shortUrlGenerator.getFullUrl(tradeNo, courierTradeOrder.getCourierId(), customerExpectedDeliveryTime);
        // 将短链-全链信息存入数据库
        ShortUrl shortUrlInfo = ShortUrl.builder()
                .shortUrl(shortUrl)
                .fullUrl(fullUrl)
                .shortCode(shortCode)
                .expireTime(customerExpectedDeliveryTime)
                .tradeNo(tradeNo)
                .build();
        shortUrlMapper.insert(shortUrlInfo);
        log.warn("短链发送：{}", shortUrl);
    }

    /**
     * 生成短链code
     *
     * @return 短链码（唯一）
     */
    public String generateShortCode(String orderNumber) {
        while (true) {
            String code = shortUrlGenerator.creatKey();
            // 判断短链码是否唯一
            long index = 0L;
            int hashCode = code.hashCode();
            if(hashCode < 0){
                index = Math.abs(hashCode) + Integer.MAX_VALUE;
            }else {
                index = hashCode;
            }
            // 利用redis的bitmap数据类型存储短链码，并判断是否唯一
            Boolean flag = redisTemplate.opsForValue().getBit(RedisConstant.TRADE_ORDER_SHORT_CODE_PREFIX + orderNumber, index);
            if(!flag){
                // false代表短链码未重复
                redisTemplate.opsForValue().setBit(RedisConstant.TRADE_ORDER_SHORT_CODE_PREFIX + orderNumber, index, true);
                return code;
            }
        }
    }

}
